/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frreport_core.c                                    */
/*  NOTE      = 把数据存储到共享内存中                             */
/*  DATE      = 2015/02/26 by guojq                                */
/*******************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#include <arpa/inet.h>
#include <json-c/json.h>

#include <zmq.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frlist.h"
#include "frbase64.h"

#include "module.h"
#include "frct_comm.h"
#include "frreport_comm.h"
#include "frreport_convert.h"
#include "frreport_params.h"
#include "frreport_dbg.h"

FR_STATIC int g_i_totools = 0;
FR_STATIC int g_i_tofile = 0;
FR_STATIC int g_i_console = 0;
FR_STATIC int g_i_base64 = 0;

//zmq初始化  0:未成功 1:成功
FR_STATIC int g_i_zmq_init = 0;
FR_STATIC pthread_spinlock_t g_sp_lock;
FR_STATIC Frlist_header *g_p_st_report_detail = NULL;
//zeromq 连接用信息
FR_STATIC void *p_st_zmq_context = NULL;
FR_STATIC void *p_st_zmq_sender=NULL;

typedef struct __st_report_stat {
    unsigned long ul_pkg_add;        //加入缓存区数据包数(包括丢弃包)
    unsigned long ul_pkg_drop;       //缓存池溢出后，丢弃的包数量
    unsigned long ul_pkg_send;       //发送的数据包

} Frreport_stat;


typedef struct __st_report_send_stat {
    unsigned long ul_stat_port_succ;
    unsigned long ul_stat_port_fail;
    unsigned long ul_stat_conn_succ;
    unsigned long ul_stat_conn_fail;
    unsigned long ul_req_succ;
    unsigned long ul_req_fail;
    unsigned long ul_resp_succ;
    unsigned long ul_resp_fail;
    unsigned long ul_pub_succ;
    unsigned long ul_pub_fail;
    unsigned long ul_sub_succ;
    unsigned long ul_sub_fail;
    unsigned long ul_notify_succ;
    unsigned long ul_notify_fail;
    unsigned long ul_unknown_succ;
    unsigned long ul_unknown_fail;
} Frreport_send_stat;


#ifdef FRDBG_PRINT_SEND
FR_STATIC int g_i_report_run = 0;
FR_STATIC Frreport_stat g_st_report_total = {0,0,0}; //ul_pkg_add不包括丢弃包
FR_STATIC Frreport_stat g_st_report_stat = {0,0,0};
FR_STATIC Frreport_stat g_st_report_info = {0,0,0};

FR_STATIC Frreport_send_stat g_st_send_stat = {0,0,0};
FR_STATIC Frreport_send_stat g_st_send_stat_info = {0,0,0};
FR_STATIC pthread_t g_thread_id_do_print=0;

FR_STATIC void __frreport_send_stat_succ_add(Frreport_data *p_st_report_data)
{
    switch (p_st_report_data->em_type)
    {
        case FRREPORT_TYPE_STAT_PORT:
            g_st_send_stat.ul_stat_port_succ++;
            return;
        case FRREPORT_TYPE_STAT_CONN:
            g_st_send_stat.ul_stat_conn_succ++;
            return;
        case FRREPORT_TYPE_L7DATA:
            break;
        default:
            g_st_send_stat.ul_unknown_succ++;
            return;
    }
    switch (p_st_report_data->em_type_l7data)
    {
        case FRREPORT_TYPE_L7DATA_REQ:
            g_st_send_stat.ul_req_succ++;
            break;
        case FRREPORT_TYPE_L7DATA_RESP:
            g_st_send_stat.ul_resp_succ++;
            break;
        case FRREPORT_TYPE_L7DATA_PUB:
            g_st_send_stat.ul_pub_succ++;
            break;
        case FRREPORT_TYPE_L7DATA_SUB:
            g_st_send_stat.ul_sub_succ++;
            break;
        case FRREPORT_TYPE_L7DATA_NOTIFY:
            g_st_send_stat.ul_notify_succ++;
            break;
        case FRREPORT_TYPE_L7DATA_UNKONWN:
            g_st_send_stat.ul_unknown_succ++;
            break;
        default:
            g_st_send_stat.ul_unknown_succ++;
            break;
    }
}

FR_STATIC void __frreport_send_stat_fail_add(Frreport_data *p_st_report_data)
{
    switch (p_st_report_data->em_type)
    {
        case FRREPORT_TYPE_STAT_PORT:
            g_st_send_stat.ul_stat_port_fail++;
            return;
        case FRREPORT_TYPE_STAT_CONN:
            g_st_send_stat.ul_stat_conn_fail++;
            return;
        case FRREPORT_TYPE_L7DATA:
            break;
        default:
            g_st_send_stat.ul_unknown_fail++;
            return;
    }
    switch (p_st_report_data->em_type_l7data)
    {
        case FRREPORT_TYPE_L7DATA_REQ:
            g_st_send_stat.ul_req_fail++;
            break;
        case FRREPORT_TYPE_L7DATA_RESP:
            g_st_send_stat.ul_resp_fail++;
            break;
        case FRREPORT_TYPE_L7DATA_PUB:
            g_st_send_stat.ul_pub_fail++;
            break;
        case FRREPORT_TYPE_L7DATA_SUB:
            g_st_send_stat.ul_sub_fail++;
            break;
        case FRREPORT_TYPE_L7DATA_NOTIFY:
            g_st_send_stat.ul_notify_fail++;
            break;
        case FRREPORT_TYPE_L7DATA_UNKONWN:
            g_st_send_stat.ul_unknown_fail++;
            break;
        default:
            g_st_send_stat.ul_unknown_fail++;
            break;
    }
}
#endif

/*******************************************************************************
*  FUNC     :  释放节点
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __list_report_node_free(Frlist_node *p_st_node)
{
    Frreport_data *p_st_report_data=NULL;
    if(p_st_node==NULL || p_st_node->data == NULL )
        return;

    p_st_report_data = (Frreport_data*)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_report_data)
    {
        frreport_data_free(&p_st_report_data);
    }

    return;
}

/*******************************************************************************
*  FUNC     :  初始化zeromq连接
*  ARGS     :
*  RTN      :  成功:FR_SUCC; 失败:FR_FAIL
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frreport_mng_conn_init(void)
{
    int i_ret_fun=0;
    //单位：毫秒
    int i_send_timeout = ZMQ_SEND_TIMEOUT;

    #ifdef FRDBG_NO_ZMQ_SEND
        return FR_SUCC;
    #endif

    p_st_zmq_context = zmq_init(1);
    if (p_st_zmq_context == NULL)
    {
        FRLOG_ERROR_DETAIL("zmq_init err");
        return FR_FAIL;
    }
    
    p_st_zmq_sender = zmq_socket(p_st_zmq_context,ZMQ_PUSH);
    if (p_st_zmq_sender == NULL)
    {
        FRLOG_ERROR_DETAIL("zmq_socket err");
        zmq_term(p_st_zmq_context);
        return FR_FAIL;
    }

    int option_sndhwm = 10000;
    zmq_setsockopt(p_st_zmq_sender, ZMQ_SNDHWM, &option_sndhwm, sizeof(option_sndhwm));

    i_ret_fun = zmq_connect(p_st_zmq_sender, st_report_params.arr_zmq_connect);
    if (i_ret_fun == 0)
    {
        zmq_setsockopt(p_st_zmq_sender, ZMQ_SNDTIMEO, &i_send_timeout, sizeof(int));
        g_i_zmq_init = 1;
        return FR_SUCC;
    }

    //出错
    if(p_st_zmq_sender)
    {
        zmq_close(p_st_zmq_sender);
        p_st_zmq_sender = NULL;
    }
    if(p_st_zmq_context)
    {
        //zmq_ctx_destroy(p_st_zmq_context);
        zmq_term(p_st_zmq_context);
        p_st_zmq_context = NULL;
    }
    FRLOG_ERROR_DETAIL("zmq_connect err");
    return FR_FAIL;

}

/*******************************************************************************
*  FUNC     :  释放zeromq连接
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frreport_mng_conn_destory(void)
{
#ifdef FRDBG_NO_ZMQ_SEND
    return;
#endif

    if(p_st_zmq_sender)
    {
        int i_zero=0;
        //有尚未发送消息也退出
        zmq_setsockopt(p_st_zmq_sender, ZMQ_LINGER, &i_zero, sizeof(int));
        zmq_close(p_st_zmq_sender);
        p_st_zmq_sender = NULL;
    }
    if(p_st_zmq_context)
    {
        //zmq_ctx_destroy(p_st_zmq_context);
        zmq_term(p_st_zmq_context);
        p_st_zmq_context = NULL;
    }

    return;
}

FR_STATIC void __frreport_encode_file(char *p_data, int i_data_len)
{
    char *p_encode = NULL;
    FILE *fp = NULL;
    struct stat buffer;
    char *p_new_name = NULL;
    int i_rtn = 0;

    if (p_data == NULL || i_data_len == 0)
        return;

    fp = fopen(st_report_params.arr_base64_file, "a");
    if (fp == NULL)
        return;

    p_encode = frbase64_encode((unsigned char *)p_data, i_data_len);
    if (p_encode == NULL)
    {
        fclose(fp);
        return;
    }

    //取得文件大小
    if (stat(st_report_params.arr_base64_file, &buffer) < 0)
    {
         fclose(fp);
         frfree(p_encode);
         return;
    }

    //文件超过指定最大长，将文件重命名，建新文件
    if ((buffer.st_size + strlen(p_encode))/1024 > st_report_params.ui_file_maxsize)
    {
    	fclose(fp);
    	//取得重命名文件名
        i_rtn = frdbg_rename_filename(st_report_params.arr_base64_file, &p_new_name);
        if (i_rtn == FR_FAIL)
        {
        	frfree(p_encode);
        	return;
        }
        //文件重命名
        i_rtn = rename(st_report_params.arr_base64_file, p_new_name);
        if (i_rtn < 0)
        {
        	frfree(p_new_name);
        	frfree(p_encode);
        	return;
        }
        frfree(p_new_name);

        //重新打开文件
        fp = fopen(st_report_params.arr_base64_file , "a");
        if (fp == NULL)
        {
            frfree(p_encode);
            return;
        }
    }

    fwrite(p_encode, strlen(p_encode), 1, fp);
    fwrite("\n", 1, 1, fp);

    fclose(fp);

    frfree(p_encode);

    return;
}


FR_STATIC void __frreport_send(Frreport_data *p_st_report_data)
{
    char *p_convert_data=NULL;
    unsigned int ui_len=0;
    int i_ret_fun=0;

    if(p_st_report_data == NULL)
        return;

    //调试用数据出力
    if (g_i_console == 1 && p_st_report_data->em_type == FRREPORT_TYPE_L7DATA)
    {
        char *p_show_data=NULL;
        unsigned int ui_show_data_len=0;
        frdbg_report_data_format(p_st_report_data, FR_YES, &p_show_data, &ui_show_data_len);

        if(p_show_data && *p_show_data != '\0')
        {
            if (g_i_console == 1)
                printf("\n[%s]\n", p_show_data);
        }
        if(p_show_data)
        {
            frfree(p_show_data);
            p_show_data = NULL;
        }
    }

    if (g_i_totools == 1 || g_i_tofile == 1)
    {
        char *p_show_data=NULL;
        unsigned int ui_show_data_len=0;
        frdbg_report_data_format(p_st_report_data, FR_NO, &p_show_data, &ui_show_data_len);

        if(p_show_data && *p_show_data != '\0')
        {
            if(ui_show_data_len > 1)
            {
                if (g_i_tofile == 1)
                	frdbg_report_data_write(st_report_params.arr_report_file, p_show_data, ui_show_data_len-1);

                if (g_i_totools == 1)
                	frdbg_report_data_send_tcp(st_report_params.arr_report_ip, st_report_params.ui_report_port , p_show_data, ui_show_data_len-1);
            }
        }
        if(p_show_data)
        {
            frfree(p_show_data);
            p_show_data = NULL;
        }
    }

    //数据转换并上报
    i_ret_fun = frreport_convert(p_st_report_data, &p_convert_data, &ui_len);
    if(p_convert_data != NULL && ui_len > 0)
    {
        if (g_i_base64 == 1)
            __frreport_encode_file(p_convert_data, ui_len);

        #ifndef FRDBG_NO_ZMQ_SEND
        if (g_i_zmq_init)
        {
            i_ret_fun = zmq_send(p_st_zmq_sender, p_convert_data, ui_len, 0);
            if (i_ret_fun < 0)
            {
                FRLOG_ERROR_DETAIL("zmq_send timeout, errno=[%s]", zmq_strerror(errno));
                #ifdef FRDBG_PRINT_SEND
                __frreport_send_stat_fail_add(p_st_report_data);
                #endif
                usleep(ZMQ_WAIT);
            }
            else
            {
                #ifdef FRDBG_PRINT_SEND
                g_st_report_stat.ul_pkg_send++;
                g_st_report_total.ul_pkg_send++;
                __frreport_send_stat_succ_add(p_st_report_data);
                #endif
            }
        }
        #endif
    }
    if(p_convert_data)
        frfree(p_convert_data);

    return;
}

//加入需要发送的详细信息
int frprint_add_report_data(Frreport_data **pp_st_report_data)
{
    Frlist_node *p_node = NULL;
    Frreport_data *p_st_report_data=NULL;

    if(pp_st_report_data == NULL || *pp_st_report_data == NULL)
        return FR_FAIL;

    p_st_report_data = *pp_st_report_data;
    if(p_st_report_data->st_data_header.arr_agent_from[0] == '\0')
        frreport_set_agent_from(p_st_report_data, st_report_params.arr_agent_from);

#ifdef FRDBG_FAST_SEND
    if (__frreport_mng_conn_init() != FR_SUCC)
        return FR_FAIL;
    __frreport_send(*pp_st_report_data);
    frreport_data_free(pp_st_report_data);
    __frreport_mng_conn_destory();
    return FR_SUCC;
#endif

    p_node = frlist_node_create(*pp_st_report_data);
    if (p_node == NULL)
    {
        FRLOG_ERROR_DETAIL("frlist_node_create err");
        goto err;
    }
#ifdef FRDBG_PRINT_SEND
    g_st_report_stat.ul_pkg_add++;
    __frreport_send_stat_succ_add(*pp_st_report_data);
#endif
    pthread_spin_lock(&g_sp_lock);
    //若超过最大条数，丢弃
    if (st_report_params.ui_report_max && g_p_st_report_detail->size + 1 > st_report_params.ui_report_max)
    {
        FRLOG_ERROR_DETAIL_LIMIT("report over flow(max=%u now=%u)", st_report_params.ui_report_max, g_p_st_report_detail->size);
        pthread_spin_unlock(&g_sp_lock);

        frfree(p_node);
        #ifdef FRDBG_PRINT_SEND
        g_st_report_stat.ul_pkg_drop++;
        g_st_report_total.ul_pkg_drop++;
        __frreport_send_stat_fail_add(*pp_st_report_data);
        #endif
        goto err;
    }
#ifdef FRDBG_PRINT_SEND
    g_st_report_total.ul_pkg_add++;
#endif
    frlist_push(g_p_st_report_detail, p_node);
    pthread_spin_unlock(&g_sp_lock);
    *pp_st_report_data = NULL;
    return FR_SUCC;
err:
    frreport_data_free(pp_st_report_data);
    return FR_FAIL;
}

//加入需要发送的连接信息
int frprint_add_report_conn(Conntrack *p_st_ct, int i_status, struct timeval st_timeval)
{
//    Frreport_data *p_st_report = NULL;
//    Frreport_conn *p_st_conn=NULL;
//
//    if(p_st_ct == NULL)
//        return FR_FAIL;
//
//    p_st_report = frmalloc(sizeof(Frreport_data));
//    if (p_st_report == NULL)
//        return FR_FAIL;
//
//    //组织数据
//    memset(p_st_report, 0x00, sizeof(Frreport_data));
//
//    if(p_st_ct)
//        p_st_report->flg_direct_known = frct_get_direct_known(p_st_ct);
//    else
//        p_st_report->flg_direct_known = FR_DIRECT_UNKNOWN;
//    p_st_report->em_data_type = FRREPORT_TYPE_CONN;
//    p_st_conn = &p_st_report->un_data.st_conn;
//
//    memcpy(p_st_conn->arr_connection_id, p_st_ct->arr_connection_id, APM_UUID_SIZE);
//    p_st_conn->ip_proto = p_st_ct->ip_proto;
//    memcpy(p_st_conn->src_mac, p_st_ct->src_mac, APM_MAC_SIZE);
//    p_st_conn->src_ip = p_st_ct->src_ip;
//    p_st_conn->src_port = p_st_ct->src_port;
//    p_st_conn->dst_ip = p_st_ct->dst_ip;
//    p_st_conn->dst_port = p_st_ct->dst_port;
//
//    /*
//        CONNECTING = 1;  //TCP syn包发出后发送connecting消息
//        ESTABLISHED = 2; //TCP三次握手后或UDP连接建立时发送established消息
//        DISCONNECT = 3; //TCP收到fin包后发送disconnect消息
//        DESTROY = 4; //连接被强制销毁时发送destroy消息
//        DATA_TIMEOUT = 5; //连接30分钟内未没有任何数据包时发送data_timeout消息
//    */
//    if(i_status == APM_CONNECT_SYN_SENT || i_status==APM_CONNECT_SYN_RECV )
//        p_st_conn->i_event = 1;
//    else if(i_status == APM_CONNECT_ESTABLISHED)
//        p_st_conn->i_event = 2;
//    else if(i_status == APM_CONNECT_CLOSED)
//            p_st_conn->i_event = 3;
//    else if(i_status == APM_CONNECT_TIMEOUT)
//        p_st_conn->i_event = 5;
//    else
//        p_st_conn->i_event = 4;
//
//    memcpy(&p_st_conn->st_timestamp, &st_timeval, sizeof(struct timeval));
//
//#ifdef FRDBG_FAST_SEND
//    __frreport_mng_conn_init();
//    __frreport_send(p_st_report);
//    frreport_free_report_data(p_st_report);
//    frfree(p_st_report);
//    __frreport_mng_conn_destory();
//    return FR_SUCC;
//#endif
//
//    if (frprint_add_report_data(p_st_report) == FR_FAIL)
//    {
//        return FR_FAIL;
//    }
    return FR_SUCC;
}

#ifdef FRDBG_PRINT_SEND
static void *__frdbg_report_stat(void *arg)
{
    unsigned int ui_pkg_add=0, ui_pkg_drop=0, ui_pkg_succ=0, ui_pkg_send=0;

    unsigned int ui_req_succ=0, ui_req_fail=0, ui_resp_succ=0, ui_resp_fail=0;
    unsigned int ui_stat_port_succ=0, ui_stat_port_fail=0, ui_stat_conn_succ=0, ui_stat_conn_fail=0;
    unsigned int ui_pub_succ=0, ui_pub_fail=0, ui_sub_succ=0, ui_sub_fail=0;
    unsigned int ui_notify_succ=0, ui_notify_fail=0, ui_unknown_succ=0, ui_unknown_fail=0;
    while (g_i_report_run)
    {
        memcpy(&g_st_report_info, &g_st_report_stat, sizeof(Frreport_stat));
        ui_pkg_add = g_st_report_info.ul_pkg_add;
        ui_pkg_drop = g_st_report_info.ul_pkg_drop;
        ui_pkg_send = g_st_report_info.ul_pkg_send;
        if(ui_pkg_add > ui_pkg_drop)
            ui_pkg_succ = ui_pkg_add - ui_pkg_drop;
        else
            ui_pkg_succ = 0;
        memset(&g_st_report_stat, 0x00, sizeof(Frreport_stat));
        FRLOG_DEBUG("report_info add queue:(max:%u used:%u) add:%u(succ:%u drop:%u)\tsend:%u"
                , st_report_params.ui_report_max, g_p_st_report_detail ? g_p_st_report_detail->size : 0
                , ui_pkg_add, ui_pkg_succ, ui_pkg_drop, ui_pkg_send );

        memcpy(&g_st_send_stat_info, &g_st_send_stat, sizeof(Frreport_send_stat));
        ui_stat_port_succ = g_st_send_stat_info.ul_stat_port_succ;
        ui_stat_port_fail = g_st_send_stat_info.ul_stat_port_fail;
        ui_stat_conn_succ = g_st_send_stat_info.ul_stat_conn_succ;
        ui_stat_conn_fail = g_st_send_stat_info.ul_stat_conn_fail;
        ui_req_succ = g_st_send_stat_info.ul_req_succ;
        ui_req_fail = g_st_send_stat_info.ul_req_fail;
        ui_resp_succ = g_st_send_stat_info.ul_resp_succ;
        ui_resp_fail = g_st_send_stat_info.ul_resp_fail;
        ui_pub_succ = g_st_send_stat_info.ul_pub_succ;
        ui_pub_fail = g_st_send_stat_info.ul_pub_fail;
        ui_sub_succ = g_st_send_stat_info.ul_sub_succ;
        ui_sub_fail = g_st_send_stat_info.ul_sub_fail;
        ui_notify_succ = g_st_send_stat_info.ul_notify_succ;
        ui_notify_fail = g_st_send_stat_info.ul_notify_fail;
        ui_unknown_succ = g_st_send_stat_info.ul_unknown_succ;
        ui_unknown_fail = g_st_send_stat_info.ul_unknown_fail;

        memset(&g_st_send_stat, 0x00, sizeof(Frreport_send_stat));
        FRLOG_DEBUG("report_info_detail: port:[succ:%u,fail:%u], stat:[succ:%u,fail:%u], request[succ:%u,fail:%u], response[succ:%u,fail:%u], pub[succ:%u,fail:%u], sub[succ:%u,fail:%u], notify[succ:%u,fail:%u], unknown[succ:%u,fail:%u]"
                    , ui_stat_port_succ, ui_stat_port_fail, ui_stat_conn_succ, ui_stat_conn_fail
                    , ui_req_succ, ui_req_fail, ui_resp_succ, ui_resp_fail, ui_pub_succ, ui_pub_fail
                    , ui_sub_succ, ui_sub_fail, ui_notify_succ, ui_notify_fail, ui_unknown_succ, ui_unknown_fail);
        sleep(1);
    }
    return NULL;
}
#endif

//初始化上报信息的共享内存
int frreport_init(void *p_context, const char *p_filename, const char *p_zmq_connect)
{
#ifdef FRDBG_FAST_SEND
    if( fr_slab_init( (Frmem_env *)(((ApmContext *)p_context)->p_st_mem_env), "report_2.0") == NULL )
    {
        frdbg("memory init err\n");
        return FR_FAIL;
    }
    frreport_params_load(p_filename);
    //设置zmq连接信息
    snprintf(st_report_params.arr_zmq_connect, sizeof(st_report_params.arr_zmq_connect), "%s", p_zmq_connect);

    g_p_st_report_detail = frlist_create();
    if (g_p_st_report_detail == NULL)
        return FR_FAIL;
    pthread_spin_init(&g_sp_lock, 0);

    return FR_SUCC;
#endif
    if (p_context ==NULL || g_p_st_report_detail || p_filename == NULL)
    {
        frdbg("report do init err\n");
        return FR_FAIL;
    }
    if( fr_slab_init( (Frmem_env *)(((ApmContext *)p_context)->p_st_mem_env), "report_2.0") == NULL )
    {
        frdbg("memory init err\n");
        return FR_FAIL;
    }
    frreport_params_load(p_filename);

    //设置zmq连接信息
    snprintf(st_report_params.arr_zmq_connect, sizeof(st_report_params.arr_zmq_connect), "%s", p_zmq_connect);

    g_p_st_report_detail = frlist_create();
    if (g_p_st_report_detail == NULL)
        return FR_FAIL;

    pthread_spin_init(&g_sp_lock, 0);

#ifdef FRDBG_PRINT_SEND
    //启动统计发送数的线程
    g_i_report_run = 1;
    pthread_create(&g_thread_id_do_print, NULL, __frdbg_report_stat, NULL);
#endif
    frdbg("frreport_init start, p_filename=[%s], zmq=[%s], agent_id=[%s] file=[%s], ip=[%s], port=%d\n"
         , p_filename, st_report_params.arr_zmq_connect
         , st_report_params.arr_agent_from
         , st_report_params.arr_report_file
         , st_report_params.arr_report_ip
         , st_report_params.ui_report_port);

    return FR_SUCC;
}

//退出释放上报信息的共享内存
int frreport_destory(void)
{
#ifdef FRDBG_FAST_SEND
    if(g_p_st_report_detail)
    {
        frlist_remove_all(g_p_st_report_detail, __list_report_node_free);
        frfree(g_p_st_report_detail);
        g_p_st_report_detail = NULL;
    }
    pthread_spin_destroy(&g_sp_lock);
    fr_slab_destroy();
    return FR_SUCC;
#endif

#ifdef FRDBG_PRINT_SEND
    g_i_report_run = 0;
    if (g_thread_id_do_print)
        pthread_join(g_thread_id_do_print, NULL);
#endif

    if(g_p_st_report_detail)
    {
        frlist_remove_all(g_p_st_report_detail, __list_report_node_free);
        frfree(g_p_st_report_detail);
        g_p_st_report_detail = NULL;
    }

    pthread_spin_destroy(&g_sp_lock);

    g_i_zmq_init = 0;

    fr_slab_destroy();

    return FR_SUCC;
}

FR_STATIC int __frreport_get_data(void)
{
    Frlist_node *p_node = NULL;
    Frreport_data *p_send_data = NULL;

    pthread_spin_lock(&g_sp_lock);
    //取得第一个节点
    p_node = frlist_pop(g_p_st_report_detail);

    pthread_spin_unlock(&g_sp_lock);

    if (p_node == NULL)
        return FR_FAIL;

    p_send_data = (Frreport_data *)p_node->data;

    //发送数据
    __frreport_send(p_send_data);

    //释放节点内容
    frreport_data_free(&p_send_data);
    frfree(p_node);

    return FR_SUCC;
}

int frreport_core(int *p_is_run)
{
#ifdef FRDBG_FAST_SEND
    return 0;
#endif
    __frreport_mng_conn_init();
    prctl(PR_SET_NAME,"report_send");
    while (*p_is_run)
    {
        if (__frreport_get_data() == FR_FAIL)
            usleep(ZMQ_WAIT);
    }
    __frreport_mng_conn_destory();

    return 0;
}

/*******************************************************************************
*  FUNC     :  取得各上报数据处理flag
*  ARGS     :
*  RTN      :  成功:FR_SUCC; 失败:FR_FAIL
*  NOTE     :
*******************************************************************************/
FR_STATIC int frreport_get_debug_data(const char *p_str, int *value)
{
	const char *p_equal = NULL;

	p_equal = strchr(p_str, '=');
	if (p_equal == NULL)
		return FR_FAIL;

	//去掉'='后面的空格
	for (p_equal = p_equal + 1; *p_equal != '\0'; p_equal++)
	{
		if (*p_equal != ' ')
			break;
	}

	if (*p_equal == '\0')
		return FR_FAIL;

	*value = atoi(p_equal);

	return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析上报数据处理flag
*  ARGS     :
*  RTN      :  成功:FR_SUCC; 失败:FR_FAIL
*  NOTE     :  0:diable; 1:enable
*           :  console:上报数据屏幕出力
*           :  testtools:数据发送测试工具
*           :  writefile:上报数据文件输出
*           :  base64: 上报web服务器的数据base64后出力文件
*           :  eg. "console=1 testtools=0 writefile=1 base64=1"
*******************************************************************************/
int frreport_debug_switch(const char *p_debugstr)
{
    int i_rtn = 0;
    int i_totools=0, i_tofile=0, i_console=0, i_base64=0;
    const char *p_index = NULL;

    if (p_debugstr == NULL || *p_debugstr == '\0')
        return FR_FAIL;

    FRLOG_INFO_DETAIL("debug switch [%s]", p_debugstr);
    i_totools = g_i_totools;
    i_tofile = g_i_tofile;
    i_console = g_i_console;
    i_base64 = g_i_base64;

    //取得上报数据显示flag
    p_index = strstr(p_debugstr, "console");
    if (p_index != NULL)
    {
        i_rtn = frreport_get_debug_data(p_index, &i_console);
        if (i_rtn == FR_FAIL)
            return FR_FAIL;
    }

    //取得上报数据发送到测试工具flag
    p_index = strstr(p_debugstr, "testtools");
    if (p_index != NULL)
    {
        i_rtn = frreport_get_debug_data(p_index, &i_totools);
        if (i_rtn == FR_FAIL)
            return FR_FAIL;
    }

    //取得上报数据保存到文件flag
    p_index = strstr(p_debugstr, "writefile");
    if (p_index != NULL)
    {
        i_rtn = frreport_get_debug_data(p_index, &i_tofile);
        if (i_rtn == FR_FAIL)
            return FR_FAIL;
    }

    //取得上报数据做base64编码后保存到文件flag
    p_index = strstr(p_debugstr, "base64");
    if (p_index != NULL)
    {
        i_rtn = frreport_get_debug_data(p_index, &i_base64);
        if (i_rtn == FR_FAIL)
            return FR_FAIL;
    }

    g_i_totools = i_totools;
    g_i_tofile = i_tofile;
    g_i_console = i_console;
    g_i_base64 = i_base64;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  上报模块统计信息
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frreport_debug_stat(char *p_outbuff, unsigned int ui_size)
{
    if(p_outbuff == NULL || ui_size <=0)
        return;

    p_outbuff[0] = '\0';

    #ifdef FRDBG_PRINT_SEND
    {
        unsigned int ui_pkg_add=0, ui_pkg_drop=0, ui_pkg_succ=0, ui_pkg_send=0;
        unsigned int ui_stat_port_succ=0, ui_stat_port_fail=0, ui_stat_conn_succ=0, ui_stat_conn_fail=0;
        unsigned int ui_req_succ=0, ui_req_fail=0, ui_resp_succ=0, ui_resp_fail=0;
        unsigned int ui_pub_succ=0, ui_pub_fail=0, ui_sub_succ=0, ui_sub_fail=0;
        unsigned int ui_notify_succ=0, ui_notify_fail=0, ui_unknown_succ=0, ui_unknown_fail=0;

        ui_pkg_add = g_st_report_info.ul_pkg_add;
        ui_pkg_drop = g_st_report_info.ul_pkg_drop;
        ui_pkg_send = g_st_report_info.ul_pkg_send;
        if(ui_pkg_add > ui_pkg_drop)
            ui_pkg_succ = ui_pkg_add - ui_pkg_drop;
        else
            ui_pkg_succ = 0;

        ui_stat_port_succ = g_st_send_stat_info.ul_stat_port_succ;
        ui_stat_port_fail = g_st_send_stat_info.ul_stat_port_fail;
        ui_stat_conn_succ = g_st_send_stat_info.ul_stat_conn_succ;
        ui_stat_conn_fail = g_st_send_stat_info.ul_stat_conn_fail;
        ui_req_succ = g_st_send_stat_info.ul_req_succ;
        ui_req_fail = g_st_send_stat_info.ul_req_fail;
        ui_resp_succ = g_st_send_stat_info.ul_resp_succ;
        ui_resp_fail = g_st_send_stat_info.ul_resp_fail;
        ui_pub_succ = g_st_send_stat_info.ul_pub_succ;
        ui_pub_fail = g_st_send_stat_info.ul_pub_fail;
        ui_sub_succ = g_st_send_stat_info.ul_sub_succ;
        ui_sub_fail = g_st_send_stat_info.ul_sub_fail;
        ui_notify_succ = g_st_send_stat_info.ul_notify_succ;
        ui_notify_fail = g_st_send_stat_info.ul_notify_fail;
        ui_unknown_succ = g_st_send_stat_info.ul_unknown_succ;
        ui_unknown_fail = g_st_send_stat_info.ul_unknown_fail;
        snprintf(p_outbuff, ui_size, "report_info queue(max:%u used:%u)\n\tadd:%u(succ:%u drop:%u)\tsend:%u\nreport_info_detail:\n\tport:[succ:%u,fail:%u], stat:[succ:%u,fail:%u], request[succ:%u,fail:%u], response[succ:%u,fail:%u], pub[succ:%u,fail:%u], sub[succ:%u,fail:%u], notify[succ:%u,fail:%u], unknown[succ:%u,fail:%u]\n"
                , st_report_params.ui_report_max, g_p_st_report_detail->size
                , ui_pkg_add, ui_pkg_succ, ui_pkg_drop, ui_pkg_send
                , ui_stat_port_succ, ui_stat_port_fail, ui_stat_conn_succ, ui_stat_conn_fail
                , ui_req_succ, ui_req_fail, ui_resp_succ, ui_resp_fail, ui_pub_succ, ui_pub_fail
                , ui_sub_succ, ui_sub_fail, ui_notify_succ, ui_notify_fail, ui_unknown_succ, ui_unknown_fail);

    }
    #endif
}

/*******************************************************************************
*  FUNC     :  上报模块统计信息
*  ARGS     :  p_st_json (json_object *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frreport_debug_stat_json(void *p_st_json)
{
    json_object *p_st_json_tmp=NULL;
    json_object *p_st_json_sub=NULL;
    if( p_st_json == NULL )
        return;

    p_st_json_tmp = (json_object *) p_st_json;

    #ifdef FRDBG_PRINT_SEND
    p_st_json_sub = json_object_new_object();
    if(p_st_json_sub == NULL)
        return;

    json_object_object_add(p_st_json_sub, "queueSize", json_object_new_int64( st_report_params.ui_report_max ));
    json_object_object_add(p_st_json_sub, "queueCounts", json_object_new_int64( g_p_st_report_detail->size ));
    json_object_object_add(p_st_json_sub, "queueAdd", json_object_new_int64( g_st_report_total.ul_pkg_add ));
    json_object_object_add(p_st_json_sub, "queueDrop", json_object_new_int64( g_st_report_total.ul_pkg_drop ));
    json_object_object_add(p_st_json_sub, "sends", json_object_new_int64( g_st_report_total.ul_pkg_send ));

    json_object_object_add(p_st_json_tmp, "report", p_st_json_sub);
    #endif

    return;
}

